package spring.datasource;

import spring.transaction.TransactionThreadManager;
import utils.LogUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;

public abstract class DataSourceUtils {

    public static void releaseConnection(Connection connection, DataSource dataSource) {
        try {
            if (Objects.isNull(connection)) {
                return;
            }
            if (Objects.nonNull(dataSource)) {
                ConnectionHolder conHolder = (ConnectionHolder) TransactionThreadManager.getResource(dataSource);
                if (Objects.nonNull(conHolder) && connectionEquals(conHolder, connection)) {
                    conHolder.released();
                    TransactionThreadManager.releaseResource();
                }
            }
        } catch (Exception ex) {
            LogUtils.debug("无法关闭 JDBC 连接。", ex);
        }
    }

    public static Connection getConnection(DataSource dataSource, boolean isUseConnection) throws SQLException {
        try {
            ConnectionHolder conHolder = (ConnectionHolder) TransactionThreadManager.getResource(dataSource);
            if (Objects.isNull(conHolder)) {
                conHolder = new ConnectionHolder();
                TransactionThreadManager.bindResource(dataSource, conHolder);
            }
            Connection connection;
            if (conHolder.hasConnection()) {
                connection = conHolder.getConnection();
            } else if (isUseConnection) {
                connection = dataSource.getConnection();
                conHolder.setConnection(connection);
                conHolder.requested();
            } else {
                return null;
            }
            return connection;
        } catch (SQLException ex) {
            throw new SQLException("Failed to obtain JDBC Connection", ex);
        } catch (IllegalStateException ex) {
            throw new SQLException("Failed to obtain JDBC Connection: " + ex.getMessage());
        }
    }

    public static Connection getConnection(DataSource dataSource) throws SQLException {
        return getConnection(dataSource, true);
    }

    public static boolean isConnectionTransactional(Connection con, DataSource dataSource) {
        if (Objects.isNull(dataSource)) {
            return false;
        }
        ConnectionHolder conHolder = (ConnectionHolder) TransactionThreadManager.getResource(dataSource);
        return (Objects.nonNull(conHolder) && connectionEquals(conHolder, con));
    }

    private static boolean connectionEquals(ConnectionHolder conHolder, Connection passedInCon) {
        if (!conHolder.hasConnection()) {
            return false;
        }
        Connection heldCon = conHolder.getConnection();
        return (heldCon == passedInCon || heldCon.equals(passedInCon));
    }

}
